package polymonkey.time;

import processing.core.*;
import java.lang.reflect.*;

/**
 * 
 *A class for automatically calling timerEvent(TimerEvent tm) methods. The method will be called at it's set time.
 *The Event is called when the current time of the TimerEvent object is greater than or equal to the the target time. 
 * 
 * @author Matt Ditton 
 * @version 1 
 */

public class TimerEvent
{	
	/**
	 * Pauses the accumulation of time to call the timerEvent(TimerEvent tm)
	 */
	public boolean pause = false;
	
	private int count = 0;

	private float currentTime = 0.0f;

	private float targetTime = 1.0f;
	
	// adding a Time so the user is forced to make "a time" in the PApplet
	@SuppressWarnings("unused")
	private Time time;	
	
	private Method timerMethod;

	private PApplet parent;
	
	private Object[] params = new Object[] { this };

	public TimerEvent(PApplet parent, Time time, float targetTime)
	{
		this.parent = parent;
		
		this.time = time;

		this.targetTime = targetTime;

		try 
		{
			timerMethod = parent.getClass().getMethod("timerEvent", new Class[] { TimerEvent.class });
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
			PApplet.println("The \"void timerEvent(TimerEvent tm)\" function is missing\nMake one and this class will call it." );
			// no such method, or an error.. which is fine, just ignore
		}

		parent.registerPre(this);		
	}

	/**
	 * Do not call this method in your sketch. pre() is registered with the PApplet to call before every draw() and collect the amount of time passed 
	 * 
	 */
	public void pre()
	{
		if(!pause)
		{
			currentTime += Time.getDeltaTime();
	
			if(atTime())
			{
				makeEvent();
				count++;
			}
		}
	}

	private boolean atTime()
	{

		if (currentTime >= targetTime)
		{
			currentTime = 0.0f;

			return true;
		}

		return false;
	}

	private void makeEvent() 
	{
		if (timerMethod != null) 
		{
			try 
			{
				timerMethod.invoke(parent, params);
			}
			catch (Exception e) 
			{
				System.err.println("Disabling timerEvent() for " + "---" + " because of an error.");
				e.printStackTrace();
				timerMethod = null;
			}
		}
	}

	/**
	 * Returns the target time of the TimerEvent in seconds.
	 * 
	 * @return The target time
	 */
	public float getTargetTime() {
		return targetTime;
	}

	/**
	 * Sets the number of seconds that the TimerEvent waits for before firing the timerEvent(TimerEvent tm). It's hopefully obvious that this value should be above 0. A value of 0 or below would result in calling the event every frame. If that's what you want then put it in the draw method.
	 * 
	 * @param targetTime the time to target
	 */
	public void setTargetTime(float targetTime) {
		this.targetTime = targetTime;
	}

	/**
	 * Gets the current time in seconds of the TimerEvent.
	 * 
	 * @return The currentTime
	 */
	public float getCurrentTime() {
		return currentTime;
	}

	/**
	 * Gives a count of the number of times the timerEvent(TimerEvent tm) has been called. This is good for only firing a method so many times. 
	 * 
	 * @return The number of times the timerEvent(TimerEvent tm) has been called
	 */
	public int getCount() {
		return count;
	}

	/**
	 * Resets the counter of the TimerEvent.
	 * 
	 * Resets the count of the number of times the timerEvent(TimerEvent tm) has been called
	 */
	public void resetCount() {
		this.count = 0;
	}
}